React 项目路由配置与跳转 您所在的位置:网站首页 react 动态import React 项目路由配置与跳转

React 项目路由配置与跳转

2023-05-29 00:23| 来源: 网络整理| 查看: 265

最近在使用 React 和 TS 搭建一个简单的项目框架,组件库使用的是 Antd5。

在配置路由的过程中出现了一些小问题,所以记录一下这个过程。

路由配置集中管理

在 src 目录下创建 routes 文件夹并创建 index.tsx 文件,引入所需依赖,并将组件映射到对应路由上,让 Router 知道在哪里渲染它们,如下:

import { lazy } from "react"; import { Outlet } from 'react-router-dom'; export interface RouteType { path: string; element: React.ReactNode; children?: Array; } const Index = lazy(() => import('@/views/Index/index')); const Information = lazy(() => import('@/views/personal/Information/index')); const Contacts = lazy(() => import('@/views/personal/Contacts/index')); const routes: Array = [ { path: '/index', element: , } { path: '/personal', element: , children: [ { path: 'information', element: }, { path: 'contacts', element: } ] } ]; export default routes;

在上述例子中,使用 React.lazy() 方法实现路由组件懒加载。路由懒加载就是把不同的路由组件分割成不同的代码块,只有在路由被访问的时候,才会加载对应组件,其实就是按需加载。使用如下:

() => import(`@/views/${component}`)

如果在某个路由下有子路由,通过 children 属性配置,如下:

const routes: Array = [ // ... { path: '/personal', element: , children: [ { path: 'information', element: }, { path: 'contacts', element: } ] } ];

其中,我们需要在渲染子组件的位置使用 Outlet 组件占位,当然也可以使用 useOutlet(),它会返回该路由组件的子路由元素。

由于我使用 Fragment 作为子组件的容器,所以直接将 Outlet 放在 Fragment 中占位。

一般情况下,父组件中还会有其他元素,此时我们需要这样设置:

import { Outlet } from 'react-router-dom'; export const Information = () => { return ( // ... // 子组件渲染出口 ) }

最后,我们使用 useRoutes() 来动态地配置路由。useRoutes() 是 React Router V6 的一个 Hook,它接收一个路由数组(也就是我们上面代码中的 routes),会根据匹配到的路由渲染相应的组件。使用如下:

import { useRoutes } from 'react-router-dom'; // 引入 useRoutes // ... const routes: Array = [...]; const WrappedRoutes = () => { return useRoutes(routes); }; export default WrappedRoutes;

到此,路由的集中管理就配置完毕。我们在 app.tsx 文件中引入 WrapperRoutes 就可以使用了。

import { BrowserRouter } from "react-router-dom"; import WrappedRoutes from '@/router/index'; const App: React.FC = () => { return ( // ... ) };

/routes/index.tsx 完整代码如下:

import { lazy } from "react"; import { Outlet, useRoutes } from 'react-router-dom'; export interface RouteType { path: string; element: React.ReactNode; children?: Array; } const Index = lazy(() => import('@/views/Index/index')); const Information = lazy(() => import('@/views/personal/Information/index')); const Contacts = lazy(() => import('@/views/personal/Contacts/index')); const routes: Array = [ { path: '/index', element: , } { path: '/personal', element: , // 使用Fragment作为子组件的容器 children: [ { path: 'information', element: }, { path: 'contacts', element: } ] } ]; const WrappedRoutes = () => { return useRoutes(routes); }; export default WrappedRoutes;

如果不使用 useRoutes(),上述功能直接使用 Routes 和 Route 也可以实现,如下:

import { lazy } from "react"; import { BrowserRouter, Routes, Route, Navigate, Outlet } from 'react-router-dom'; const Index = lazy(() => import('@/views/Index/index')); const Information = lazy(() => import('@/views/personal/Information/index')); const Contacts = lazy(() => import('@/views/personal/Contacts/index')); // ... const App: React.FC = () => { return ( ) }

关于 path 的写法:V6 中的嵌套路由可以只定义相对父路由的相对路径,内部会为我们自动拼接全路径。

Menu 组件实现路由跳转

导航菜单我使用的是 Antd 的 Menu 组件。

首先,我们定义一个类型为 Array 的 menuList,用于导航菜单的展示,如下:

// ... import WrappedRoutes from '@/router/index'; // 引入路由表 type MenuItem = { label: string, key: string, icon?: React.ReactNode children?: Array } const menuList: Array = [{ label: "首页", key: "/index", icon: , }, { label: "个人办公", key: "/personal", icon: , children: [ { label: "个人信息", icon: , key: "/personal/information" }, { label: "通讯录", icon: , key: "/personal/contacts" } ] }] const App: React.FC = () => { return ( setCollapsed(value)}> ) }; export default App;

image.png

但是,此时点击菜单项不能跳转到对应的路由。怎么实现路由跳转呢?

在 Menu 组件上可以绑定点击事件,通过它我们可以获取 key、keyPath 等属性。

const App = () => { const handleClick = (e: any) => { console.log(e); console.log('key', e.key); } return ( // ... ) }

image.png

点击“个人信息”选项,可以看到,key 属性就是我们要跳转到的路由组件对应的完整路径 /personal/information。

接下来,我们在 handleClick 函数中使用 useNavigate() 根据对应的路由实现跳转。此时,结合 useLocation() 实时获取并保存当前 url,并交给 Menu 组件的 selectedKeys 属性,保持当前选中项的激活状态。

import { useLocation, useNavigate } from 'react-router-dom'; const App = () => { const navigate = useNavigate(); const { pathname } = useLocation(); // 获取当前url const handleClick = (e: any) => { navigate(e.key); // 实现跳转 } return ( // ... ) }

这样就可以实现路由跳转了。

image.png

Breadcrumb 组件根据 Route 动态切换

首先,根据上面配置好的 menuList,实现 getBreadcrumbNameMap,生成 key 和 label 的映射关系。

export const breadcrumbMap: Map = new Map(); function getBreadcrumbNameMap(breadcrumbMap: Map) { for (let menuItem of menuList) { breadcrumbMap.set(menuItem.key, menuItem.label); if (menuItem.children) { for (let child of menuItem.children) { breadcrumbMap.set(child.key, child.label); } } } } console.log(breadcrumbMap);

image.png

我们已经使用 useLocation 获取了当前 location 对象并解构出了当前路由组件对应的 url,也就是 pathname。

接下来,将 pathname 以 / 字符分割并逐节遍历,在 breadcrumbMap 中寻找对应的 label,找到了就拼接下一段,继续在 breadcrumbMap 中匹配 label,以此类推,直到遍历完成。

const App = () => { const { pathname } = useLocation(); const pathSnippets = pathname.split('/').filter((i) => i); const breadcrumbItems = pathSnippets.map((_, index) => { const url = `/${pathSnippets.slice(0, index + 1).join('/')}`; console.log(url); return { key: url, title: {breadcrumbMap.get(url)}, }; }); return ( // ... ) }

image.png

最后即可成功获取当前路由对应的面包屑导航,效果如上。

最后

前端新手记录一下自己的使用体验,如果有什么不对的地方欢迎指正~



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有